package aeronef.builder;

import aeronef.appStates.GameState;
import aeronef.model.Battery;
import aeronef.model.Turret;
import aeronef.model.Ship;
import com.jme3.app.state.AppStateManager;
import com.jme3.asset.AssetManager;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.material.Material;
import com.jme3.math.FastMath;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.Spatial.CullHint;
import org.w3c.dom.Element;

/**
 *
 * @author Hagan
 */
public class ShipBuilder extends AbstractBuilder {
    
    TurretBuilder turretBuilder;
    FunnelBuilder funnelBuilder;
    
    Ship ship;
    Spatial shipGeo;
    

    public ShipBuilder(GameState gameState) {
        super(gameState);
        turretBuilder = new TurretBuilder(gameState);
        funnelBuilder = new FunnelBuilder(gameState);
    }

    public Ship buildFromDefinition(String name, String type) {

        String definitionString = (String) assetManager.loadAsset("Data/ships/" + type + ".xml");
        definition = buildDocument(definitionString);
        
        ship = createShip(name);
        addBatteries();
        addFunnels();

        return ship;
    }

    private Ship createShip(String name) {

        ship = new Ship(stateManager);
        ship.setName(name);
        buildShipProperties();
        buildHullGeometry();
        addPhysics();
        
        buildTargeter();
        
        return ship;
    }
    
    private void buildShipProperties() {
       ship.setForwardThrust(getTagValueAsFloat("forwardThrust", definition.getDocumentElement()));
       ship.setTurnThrust(getTagValueAsFloat("turnThrust", definition.getDocumentElement()));
    }
    
    private void buildTargeter() {
       Node targeterNode = new Node();
       targeterNode.setCullHint(CullHint.Never);
       ship.attachChild(targeterNode);
       ship.setTargeterNode(targeterNode);
       
       Spatial targeterGeo = assetManager.loadModel("Models/targeter.j3o");
       Material mat = new Material(assetManager, "Common/MatDefs/Misc/ShowNormals.j3md"); // default material
       targeterGeo.setMaterial(mat);
       targeterNode.attachChild(targeterGeo);
    }
    
    private void buildHullGeometry() {
        String mesh = getTagValue("mesh", definition.getDocumentElement());
        shipGeo = assetManager.loadModel("Models/ships/hulls/" + mesh + ".j3o");
        Material mat = new Material(assetManager, "Common/MatDefs/Misc/ShowNormals.j3md"); // default material
        shipGeo.setMaterial(mat);
        ship.attachChild(shipGeo);
    }
    
    private void addPhysics() {
        RigidBodyControl shipPhysics = new RigidBodyControl(7);
        ship.addControl(shipPhysics);
        shipPhysics.setDamping(new Float(0.5), new Float(0.6));
        
        BulletAppState bulletAppState = stateManager.getState(BulletAppState.class);
        bulletAppState.getPhysicsSpace().add(shipPhysics);
    }
    
    private void addBatteries() {
        for (Element batteryElement : getElementsByTagName(definition.getDocumentElement(), "battery")) {
            Battery battery = new Battery();
            String name = getTagValue("turnRate", batteryElement);
            battery.setName(name);
            for (Element turretElement : getElementsByTagName(batteryElement, "turret")) {
                addTurretToBattery(turretElement, battery);
            }
            ship.getBatteries().add(battery);
        }
    }
    
    private void addTurretToBattery(Element turretElement, Battery battery) {
        
        //attach
        String name = getTagValue("name", turretElement);
        String type = getTagValue("type", turretElement);
        Turret turret = turretBuilder.buildFromDefinition(name, type, ship);
        battery.getTurrets().add(turret);
        ship.attachChild(turret);

        //position
        Float xPos = getTagValueAsFloat("xPos", turretElement);
        Float yPos = getTagValueAsFloat("yPos", turretElement);
        Float zPos = getTagValueAsFloat("zPos", turretElement);
        turret.move(xPos, yPos, zPos);
        
        //rotate to rest
        Float rotation = getTagValueAsFloat("rotation", turretElement);
        if (rotation != null) { 
            turret.rotate(0, rotation*FastMath.DEG_TO_RAD, 0); 
        }
        
        //set movement
        turret.setTraverseArc(getTagValueAsFloat("traverseArc", turretElement));
    }

    private void addFunnels() {

        for (Element element : getElementsByTagName(definition.getDocumentElement(), "funnel")) {

            //attach
            String type = getTagValue("type", element);
            Node funnelNode = funnelBuilder.buildFromDefinition("", type);
            ship.attachChild(funnelNode);

            //position
            Float xPos = getTagValueAsFloat("xPos", element);
            Float yPos = getTagValueAsFloat("yPos", element);
            Float zPos = getTagValueAsFloat("zPos", element);
            funnelNode.move(xPos, yPos, zPos);
        }
    }
}
